package com.pan.handle.req.impl;

import com.pan.entity.HumbleHttpRequest;
import com.pan.handle.config.HttpConfig;
import com.pan.handle.req.RequestHandle;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HumbleHttpReqHandle implements RequestHandle<HumbleHttpRequest>, HttpConfig {
    //Multiple thread share this class instance. Please do not include status in this class

//    private AtomicBoolean hasNext = new AtomicBoolean(true);//delete
    @Override
    public HumbleHttpRequest receive(Socket socket) {
        HumbleHttpRequest request = new HumbleHttpRequest();
        InputStream inputStream = null;
        try {
            //Set Timeout
            socket.setSoTimeout(getHttpConnectTime()*1000);
            inputStream = socket.getInputStream();
        } catch (IOException e) {
            System.out.println("socket connection fail");
            return null;
            //            throw new RuntimeException(e);
        }
        String httpMessage = "";
        while (true) {
            byte[] buf = new byte[2048];
            int bufLen = 0;
            try {
                bufLen = inputStream.read(buf);
            } catch (IOException e) {
                //This is the Connection timeout Processing Code
                System.out.println("Read Timeout error");
//                hasNext.set(false);
                return null;
            }
            if (bufLen == -1){
                System.out.println(request.toString());
                return null;
            }
            httpMessage += new String(buf, 0, bufLen);
            int firstLineIndex = httpMessage.indexOf("\r\n");
            if (firstLineIndex == -1) {
                continue;
            } else {
                if (request.getUrl() == null) {
                    String firstLine = httpMessage.substring(0, firstLineIndex);
                    //The structure of the first line of an HTTP message:
                    //RequestMethod space Url space HttpVersion
                    Pattern pattern = Pattern.compile("^((?i)get|post|put|delete)\\s(/.*)\\s((?i)https?/\\d\\.\\d)$");//, Pattern.CASE_INSENSITIVE);
                    Matcher matcher = pattern.matcher(firstLine);
                    if (matcher.find()){
//                        debug
//                        System.out.println(matcher.group());
                        request.setMethod(matcher.group(1));
                        //processing the url
                        String url = matcher.group(2);
                        request.setUrl(url);
                        //if this has parameter
                        if (url.indexOf("?")!=-1) {
                            //processing the parameter
                            Matcher urlMatcher = Pattern.compile("\\w+\\=.*?(?=$|&)").matcher(url);
                            for (;urlMatcher.find();){
                                String kv = urlMatcher.group();
                                int eqIdx = kv.indexOf("=");
                                request.addUrlParameter(kv.substring(0,eqIdx),kv.substring(eqIdx+1));
                            }
                        }
                        //matcher.group(3) //This is the HttpVersion
                    }else {
                        //This isn't an HTTP Message
//                        hasNext.set(false);
                        return null;
                    }
                }
            }
            int neck = httpMessage.indexOf("\r\n\r\n");
            if (neck != -1) {
                //has header
                String header = httpMessage.substring(firstLineIndex + 2, neck);
                Pattern contentLengthPattern = Pattern.compile("(?<=Content-Length:\\s)\\d+");
                Matcher matcher = contentLengthPattern.matcher(header);
                if (matcher.find()) {
                    //has body
                    int bodyLength = Integer.parseInt(matcher.group());
                    if (neck + 4 + bodyLength == bufLen) {
                        String body = httpMessage.substring(httpMessage.length() - bodyLength);
                        //This is the HttpBody processing code
                        request.setBody(body);
                    } else {
                        //The length of body is less than Content-Length, so the http transmission is incomplete
                        continue;
                    }
                }
                //This is header processing code
                String[] attributeLine = header.split("\r\n");
                for (int i = 0; i < attributeLine.length; i++) {
                    String line = attributeLine[i];
                    //This is http attribute processing code
                    int index = line.indexOf(": ");
                    String key = line.substring(0, index);
                    String value = line.substring(index + 2);
                    request.addHttpAttribute(key, value);
                }
                break;
            } else {
                //hasn't header, so the transmission is incomplete
                continue;
            }
        }
        return request;
    }

//    delete
//    @Override
//    public boolean hasNext() {
//        return hasNext.get();
//    }
}
